DOM XSS in jQuery anchor href attribute sink using location.search source
Abuso de un sink jQuery .attr('href') controlado por location.search: el parámetro returnPath se inyecta como javascript:alert(document.cookie) en el enlace Back.
Target Overview & Vulnerability Summary
El laboratorio contiene un DOM XSS en la página de envío de feedback. jQuery selecciona un elemento ancla con el selector $ y cambia su atributo href usando datos de location.search (parámetro returnPath). Al inyectar un esquema javascript:, el enlace "Back" ejecuta código cuando la víctima hace clic.
| Campo | Valor |
|---|---|
| Severidad | Media-Alta (ejecución de JavaScript al interactuar con el enlace) |
| Endpoint vulnerable | /feedback (parámetro returnPath) |
| Root cause | Sink jQuery .attr() sobre href con source location.search sin validación de esquema |
Technical Breakdown & Exploitation Flow
1. El sink
Dentro de la ruta de feedback:
<script>
$(function() {
$('#backLink').attr("href", (new URLSearchParams(window.location.search)).get('returnPath'));
});
</script>
attr()es la función de jQuery que manipula atributos del DOM.- El selector
$('#backLink')encuentra el elemento ancla del enlace "Back". - El valor del parámetro
returnPathde la URL se asigna directo al atributohref.
2. Payload
URL/feedback?returnPath=javascript:alert(document.cookie)
Al asignar href = "javascript:alert(document.cookie)", el enlace "Back" adquiere un esquema pseudo-protocolo. Cuando el usuario hace clic, el navegador interpreta el esquema javascript: y ejecuta el código en el contexto del documento.
Root Cause Analysis
El defecto es asignar a un atributo de URL (contexto de destino de navegación) un valor controlado por el usuario sin validar el esquema. El navegador distingue protocolos activos (javascript:, data:, vbscript:) de esquemas seguros (https:, mailto:), y un href acepta cualquiera de ellos. location.search es un source directamente modificable desde la URL, y el sink .attr('href') no aplica ningún filtro.
Secure Remediation
- Validar el esquema del
returnPathantes de asignarlo:
$(function() {
const returnPath = new URLSearchParams(window.location.search).get('returnPath');
if (returnPath && returnPath.startsWith('/')) {
$('#backLink').attr("href", returnPath);
}
});
- Idealmente, resolver el
returnPathserver-side contra una lista blanca de rutas internas y nunca reflejarlo sin validar. La regla es: cualquier atributo que contenga una URL debe usar un esquema de lista blanca (https:, rutas relativas) y nunca aceptar protocolos activos. - Como refuerzo, CSP
script-srcque bloqueejavascript:URLs inline o navegación a esquemas activos.